//
//  ApiHelper.swift
//  NoiseCloud
//
//  Created by Hu Gang on 2021/2/6.
//

import Foundation
import UIKit

struct ImageInfo {
    var image : UIImage
    var filename : String
}

// api返回错误
enum NetworkError:Error {
    case transportError(Error)
    case serverError(statusCode:Int,message:String)
    case noData
    case decodingError(Error)
    case encodingError(Error)
}

class ApiHelper {
    static func getRequest<T: Decodable>(url: String, completion: @escaping(Result<T, NetworkError>) -> Void) {
        print("")
        print("================= Http Get ================")
        let url0 = url.replacingOccurrences(of: "\n", with: "").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        print("[API] url  : \(url0 ?? "")")
        let url1 = URL(string:url0!)
        URLSession.shared.dataTask(with: url1!) { (data, response, err) in
            print("[API] ----------------- Response ---------------- \(response)")
            if let error = err {
                completion(.failure(.transportError(error)))
                return
            }
            
            if let response = response as? HTTPURLResponse,!(200...299).contains(response.statusCode) {
                completion(.failure(.serverError(statusCode: response.statusCode, message: String(decoding: data!, as: UTF8.self))))
                return
            }
            
            guard var data = data else {
                completion(.failure(.noData))
                return
            }
            
            do {
               print("[API](\(String(describing: url1)) Response:\(String(data: data, encoding: .utf8)!)")
                if (url.contains("/mytalkmessage?") && String(decoding: data, as: UTF8.self) == "-1") {
                    data = Data("[]".utf8)
                }
                let obj = try JSONDecoder().decode(T.self, from: data)
                completion(.success(obj))
            } catch let jsonErr {
                print("[API] (\(String(describing: url1)) Failed to decode json:", jsonErr)
                completion(.failure(.decodingError(jsonErr)))
            }
        }.resume()
    }
    
    static func postRequest<T:Decodable>(url: String, postData: Data, completion: @escaping(Result<T, NetworkError>) -> Void)
    {
        print("================= Http Post ================")
        print("url  : \(url)")
        print("data :\(String(data: postData, encoding: .utf8)!)")
        
        let url = URL(string: url)
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        request.httpBody = postData
        
        URLSession.shared.dataTask(with: request) {
            data, response, err in
            print(" ----------------- Response ---------------- ")
            //print("data:\(data)")
            //print("response:\(response)")
//            print("err:\(err?.localizedDescription)")
            if let error = err {
                completion(.failure(.transportError(error)))
                return
            }
            
            if let response = response as? HTTPURLResponse,!(200...299).contains(response.statusCode) {
                completion(.failure(.serverError(statusCode: response.statusCode, message: String(decoding: data!, as: UTF8.self))))
                return
            }
            
            if let data = data {
                do {
                    print("Result:\(String(data: data, encoding: .utf8)!)")
                    let obj = try JSONDecoder().decode(T.self, from: data)
                    completion(.success(obj))
                } catch let jsonErr {
                    print("Failed to decode json:", jsonErr)
                    completion(.failure(.decodingError(jsonErr)))
                }
            }
            print(" ================= POST OVER ================")
        }.resume()
    }

    
    static func uploadImage<T:Decodable>(url: String, image:ImageInfo, completion: @escaping(Result<T, NetworkError>) -> Void)
    {
        print("================= Http Post Multipart ================")
        print("url  : \(url)")
        
        let url = URL(string: url)
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"
        let boundary = "Boundary-\(UUID().uuidString)"
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        
        let body = NSMutableData()
        let boundaryPrefix = "--\(boundary)\r\n"

        let mimeType = "image/jpg"
        
        var filename = String()

            filename = image.filename
            body.appendString(boundaryPrefix)
            body.appendString("Content-Disposition: form-data; name=\"picture\"; filename=\"\(filename)\"\r\n")
            body.appendString("Content-Type: \(mimeType)\r\n\r\n")
            
    let data = image.image.jpegData(compressionQuality: 0.6)! // 图片压缩率
            body.append(data)
            body.appendString("\r\n")

        body.appendString("--".appending(boundary.appending("--")))
        
        request.httpBody = body as Data
        
        URLSession.shared.dataTask(with: request) {
            data, response, err in
            print(" ----------------- Response ---------------- ")
            if let error = err {
                completion(.failure(.transportError(error)))
                return
            }
            
            if let response = response as? HTTPURLResponse,!(200...299).contains(response.statusCode) {
                completion(.failure(.serverError(statusCode: response.statusCode, message: String(decoding: data!, as: UTF8.self))))
                return
            }
            
            if let data = data {
                do {
                    //print("Result:\(String(data: data, encoding: .utf8)!)")
                    let obj = try JSONDecoder().decode(T.self, from: data)
                    completion(.success(obj))
                } catch let jsonErr {
                    print("Failed to decode json:", jsonErr)
                    completion(.failure(.decodingError(jsonErr)))
                }
            }
            print(" ================= POST OVER ================")
        }.resume()
    }

    static func uploadMp3<T:Decodable>(url: String, mp3Filename:String, completion: @escaping(Result<T, NetworkError>) -> Void)
    {
    print("================= Http Post Multipart Mp3 ================")
    print("url  : \(url)")

    let url = URL(string: url)
    var request = URLRequest(url: url!)
    request.httpMethod = "POST"
    let boundary = "Boundary-\(UUID().uuidString)"
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

    let body = NSMutableData()
    let boundaryPrefix = "--\(boundary)\r\n"

    let mimeType = "audio/mpeg"

    var filename = String()

    filename = mp3Filename
    body.appendString(boundaryPrefix)
    body.appendString("Content-Disposition: form-data; name=\"picture\"; filename=\"\(filename)\"\r\n")
    body.appendString("Content-Type: \(mimeType)\r\n\r\n")

    let data = try! Data(contentsOf: URL(fileURLWithPath: mp3Filename))
    
    body.append(data)
    body.appendString("\r\n")

    body.appendString("--".appending(boundary.appending("--")))

    request.httpBody = body as Data

    URLSession.shared.dataTask(with: request) {
        data, response, err in
        print(" ----------------- Response ---------------- ")
        if let error = err {
            completion(.failure(.transportError(error)))
            return
        }

        if let response = response as? HTTPURLResponse,!(200...299).contains(response.statusCode) {
            completion(.failure(.serverError(statusCode: response.statusCode, message: String(decoding: data!, as: UTF8.self))))
            return
        }

        if let data = data {
            do {
                //print("Result:\(String(data: data, encoding: .utf8)!)")
                let obj = try JSONDecoder().decode(T.self, from: data)
                completion(.success(obj))
            } catch let jsonErr {
                print("Failed to decode json:", jsonErr)
                completion(.failure(.decodingError(jsonErr)))
            }
        }
        print(" ================= POST OVER ================")
    }.resume()
    }

  static func uploadImages<T:Decodable>(url: String, params: [String : String]?, images:[ImageInfo], completion: @escaping(Result<T, NetworkError>) -> Void)
  {
print("================= Http Post Multipart ================")
print("url  : \(url)")

let url = URL(string: url)
var request = URLRequest(url: url!)
request.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

let body = NSMutableData()
let boundaryPrefix = "--\(boundary)\r\n"
if let params = params {
  for (key, value) in params {
    body.appendString(boundaryPrefix)
    body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
    body.appendString("\(value)\r\n")
  }
}

let mimeType = "image/jpg"

var filename = String()
for (index,img) in images.enumerated(){
  filename = img.filename
  body.appendString(boundaryPrefix)
  body.appendString("Content-Disposition: form-data; name=\"image\(index)\"; filename=\"\(filename)\"\r\n")
  body.appendString("Content-Type: \(mimeType)\r\n\r\n")

  let data = img.image.jpegData(compressionQuality: 1.0)!
  body.append(data)
  body.appendString("\r\n")
}
body.appendString("--".appending(boundary.appending("--")))

request.httpBody = body as Data

URLSession.shared.dataTask(with: request) {
  data, response, err in
  print(" ----------------- Response ---------------- ")
  if let error = err {
    completion(.failure(.transportError(error)))
    return
  }

  if let response = response as? HTTPURLResponse,!(200...299).contains(response.statusCode) {
    completion(.failure(.serverError(statusCode: response.statusCode, message: String(decoding: data!, as: UTF8.self))))
    return
  }

  if let data = data {
    do {
      //print("Result:\(String(data: data, encoding: .utf8)!)")
      let obj = try JSONDecoder().decode(T.self, from: data)
      completion(.success(obj))
    } catch let jsonErr {
      print("Failed to decode json:", jsonErr)
      completion(.failure(.decodingError(jsonErr)))
    }
  }
  print(" ================= POST OVER ================")
}.resume()
  }
    
    static func postSafeRequest<T:Decodable>(url: String, token: UUID, postData: Data, completion: @escaping(Result<T, NetworkError>) -> Void)
    {
        print("================= Http Safe Post ================")
        print("url  : \(url)")
        print("data :\(String(data: postData, encoding: .utf8)!)")
        
        let requstUrl = URL(string: url)
        var request = URLRequest(url: requstUrl!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        let nonce = Nonce()
        print("nonce : \(nonce)")
        let timestamp = (Int)(Date().timeIntervalSince1970)
        print("timestamp : \(timestamp)")
        
        let signString = "nonce=\(nonce)&timestamp=\(timestamp)&token=\(token.uuidString)&url=\(url)"
        let signature = Md5Helper.MD5String(string: signString).uppercased()
        
        let headers = [
            "token": "\(token.uuidString)",
            "nonce": "\(nonce)",
            "timestamp": "\(timestamp)",
            "signature": signature
        ]
        
        request.allHTTPHeaderFields = headers
        request.httpBody = postData
        print("postData:\(postData)")
        autoreleasepool {
            URLSession.shared.dataTask(with: request) {
                data, response, err in
                print(" ----------------- Response ---------------- ")
                if let error = err {
                    completion(.failure(.transportError(error)))
                    return
                }
                
                if let response = response as? HTTPURLResponse,!(200...299).contains(response.statusCode) {
                    completion(.failure(.serverError(statusCode: response.statusCode, message: String(decoding: data!, as: UTF8.self))))
                    return
                }
                
                if let data = data {
                    do {
                        //print("Result:\(String(data: data, encoding: .utf8)!)")
                        let obj = try JSONDecoder().decode(T.self, from: data)
                        completion(.success(obj))
                    }
                    catch DecodingError.keyNotFound(let key, let context) {
                        Swift.print("could not find key \(key) in JSON: \(context.debugDescription)")
                    } catch DecodingError.valueNotFound(let type, let context) {
                        Swift.print("could not find type \(type) in JSON: \(context.debugDescription)")
                    } catch DecodingError.typeMismatch(let type, let context) {
                        Swift.print("type mismatch for type \(type) in JSON: \(context.debugDescription)")
                    } catch DecodingError.dataCorrupted(let context) {
                        Swift.print("data found to be corrupted in JSON: \(context.debugDescription)")
                    } catch let error as NSError {
                        NSLog("Error in read(from:ofType:) domain= \(error.domain), description= \(error.localizedDescription)")
                    }
                    catch let jsonErr {
                        print("Failed to decode json:", jsonErr)
                        completion(.failure(.decodingError(jsonErr)))
                    }
                }
                print(" ================= POST OVER ================")
            }.resume()
            
        }
        usleep(60000)
    }
}
